package ru.ifmo.network.skype.network;

import org.apache.log4j.Logger;
import ru.ifmo.network.skype.UserData;
import ru.ifmo.network.skype.UserDataResolver;
import ru.ifmo.network.skype.network.data.Group;
import ru.ifmo.network.skype.network.data.TCPCommand;
import ru.ifmo.network.skype.network.data.UserAddress;

import java.io.*;
import java.net.Socket;

import static ru.ifmo.network.skype.network.NetworkUtils.writeInt;

/**
 * @author avhaliullin
 */
public class TCPClient implements UserDataResolver {
    private static final Logger log = Logger.getLogger(TCPClient.class);
    private final SecureConnectionManager secureConnectionManager;
    private final int port;

    public TCPClient(int port, SecureConnectionManager secureConnectionManager) {
        this.port = port;
        this.secureConnectionManager = secureConnectionManager;
    }

    private Channel createSecureChannel(UserAddress userAddress) throws IOException {
        final Channel channel = createSimpleChannel(userAddress);
        writeInt(channel.getOutputStream(), TCPCommand.SECURE.getValue());
        return secureConnectionManager.wrap(channel);
    }

    private Channel createSimpleChannel(UserAddress userAddress) throws IOException {
        final Socket socket = new Socket(userAddress.getIpAddress(), port);
        return new Channel() {
            @Override
            public InputStream getInputStream() throws IOException {
                return socket.getInputStream();
            }

            @Override
            public OutputStream getOutputStream() throws IOException {
                return socket.getOutputStream();
            }

            @Override
            public void close() {
                try {
                    socket.close();
                } catch (IOException e) {
                    //ignore
                }
            }
        };
    }

    public void invite(UserAddress userAddress, Group group) {
        try {
            Channel channel = createSecureChannel(userAddress);
            writeInt(channel.getOutputStream(), TCPCommand.GROUP.getValue());
            ObjectOutputStream out = new ObjectOutputStream(channel.getOutputStream());
            group.writeExternal(out);
            channel.close();
        } catch (IOException e) {
            log.error(e);
        }
    }

    @Override
    public UserData getUserData(UserAddress address) {
        Channel channel = null;
        try {
            System.out.println("Getting " + address.getIpAddress().toString());
            channel = createSimpleChannel(address);
            writeInt(channel.getOutputStream(), TCPCommand.USER_DATA.getValue());
            UserData userData = new UserData(address);
            userData.readExternal(new ObjectInputStream(channel.getInputStream()));
            System.out.println("Done " + address.getIpAddress().toString());
            return userData;
        } catch (Exception e) {
            log.error(e);
            return null;
        } finally {
            if (channel != null) {
                channel.close();
            }
        }
    }
}
